////////////////////////////////////////////////////////////////////////////
//
//  Crytek Engine Source File.
//  Copyright (C), Crytek Studios, 2001-2006.
// -------------------------------------------------------------------------
//  File name:   MaterialHUDFXNodes.cpp
//  Version:     v1.00
//  Created:     29-11-2006 by AlexL - Benito GR
//  Compilers:   Visual Studio.NET 2003
//  Description: 
// -------------------------------------------------------------------------
//  History:
//
////////////////////////////////////////////////////////////////////////////

#include "StdAfx.h"
#include "MaterialEffects.h"
#include <FlowSystem/Nodes/FlowBaseNode.h>
#include "IFlashPlayer.h"

//CHUDStartFXNode
//Special node that let us trigger a FlowGraph HUD effect related to 
//some kind of material, impact, explosion...
class CHUDStartFXNode : public CFlowBaseNode<eNCT_Singleton>
{
public:
	CHUDStartFXNode(SActivationInfo* pActInfo)
	{
	}

	~CHUDStartFXNode()
	{
	}

	enum 
	{
		EIP_Trigger = 0,
	};

	enum
	{
		EOP_Started = 0,
		EOP_Distance,
		EOP_Param1,
		EOP_Param2,
		EOP_Intensity,
	};

	virtual void GetMemoryUsage(ICrySizer * s) const
	{
		s->Add(*this);
	}

	void GetConfiguration( SFlowNodeConfig& config )
	{
		static const SInputPortConfig in_config[] = {
			InputPortConfig_Void  ("Start",_HELP("Triggered automatically by MaterialEffects")),
			InputPortConfig_Null()
		};
		static const SOutputPortConfig out_config[] = {
			OutputPortConfig_Void   ("Started",_HELP("Triggered when Effect is started.")),
			OutputPortConfig<float> ("Distance",_HELP("Distance to player")),
			OutputPortConfig<float> ("Param1",_HELP("MFX Custom Param 1")),
			OutputPortConfig<float> ("Param2",_HELP("MFX Custom Param 2")),
			OutputPortConfig<float> ("Intensity",_HELP("Dynamic value set from game code (0.0 - 1.0)")),
			OutputPortConfig<float> ("BlendOutTime", _HELP("Outputs time value in seconds; request to blend out FX in that time")),
			OutputPortConfig_Null()
		};
		config.sDescription = _HELP("MaterialFX StartNode");
		config.pInputPorts = in_config;
		config.pOutputPorts = out_config;
		config.SetCategory(EFLN_APPROVED);
	}

	//Just activate the output when the input is activated
	void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
	{
		switch (event)
		{
		case eFE_Initialize:
			break;
		case eFE_Activate:
			if (IsPortActive(pActInfo, EIP_Trigger))
				ActivateOutput(pActInfo, EOP_Started, true);
			break;
		}
	}

};

//CHUDEndFXNode
//Special node that let us know when the FlowGraph HUD Effect has finish
class CHUDEndFXNode : public CFlowBaseNode<eNCT_Singleton>
{
public:
	CHUDEndFXNode(SActivationInfo* pActInfo)
	{
	}

	~CHUDEndFXNode()
	{
	}

	enum 
	{
		EIP_Trigger = 0,
	};

	void GetConfiguration( SFlowNodeConfig& config )
	{
		static const SInputPortConfig in_config[] = {
			InputPortConfig_Void     ("Trigger", _HELP("Trigger to mark end of effect.")),
			InputPortConfig_Null()
		};
		config.sDescription = _HELP("MaterialFX EndNode");
		config.pInputPorts = in_config;
		config.pOutputPorts = 0;
		config.SetCategory(EFLN_APPROVED);
	}

	//When activated, just notify the MaterialFGManager that the effect ended
	//See MaterialFGManager.cpp
	void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
	{
		switch (event)
		{
		case eFE_Initialize:
			break;
		case eFE_Activate:
			if (IsPortActive(pActInfo, EIP_Trigger))
			{
				CMaterialEffects* pMatFX = static_cast<CMaterialEffects*> (gEnv->pGame->GetIGameFramework()->GetIMaterialEffects());
				if (pMatFX)
				{
					//const string& name = GetPortString(pActInfo, EIP_Name);
					pMatFX->NotifyFGHudEffectEnd(pActInfo->pGraph);
				}
			}
			break;
		}
	}

	virtual void GetMemoryUsage(ICrySizer * s) const
	{
		s->Add(*this);
	}
};


class CMaterialFlashInvokeNode : public CFlowBaseNode<eNCT_Singleton>
{
public:
	CMaterialFlashInvokeNode(SActivationInfo* pActInfo)
	{
	}

	~CMaterialFlashInvokeNode()
	{
	}

	enum 
	{
		EIP_Trigger = 0,
		EIP_Function,
		EIP_Int,
		EIP_Float,
	};

	void GetConfiguration( SFlowNodeConfig& config )
	{
		static const SInputPortConfig in_config[] = {
			InputPortConfig_Void		("Trigger", _HELP("Trigger the Invoke.")),
			InputPortConfig<string> ("Function", _HELP("Function Name")),
			InputPortConfig<int>		("Integer", 0, _HELP("INTEGER parameter")),
			InputPortConfig<float>	("Float", 0.0f, _HELP("FLOAT parameter")),
			InputPortConfig_Null()
		};
		config.nFlags |= EFLN_TARGET_ENTITY;
		config.sDescription = _HELP("Material Flash Invoke");
		config.pInputPorts = in_config;
		config.pOutputPorts = 0;
		config.SetCategory(EFLN_APPROVED);
	}

	//When activated, just notify the MaterialFGManager that the effect ended
	//See MaterialFGManager.cpp
	void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
	{
		switch (event)
		{
		case eFE_Initialize:
			break;
		case eFE_Activate:
			if (IsPortActive(pActInfo, EIP_Trigger))
			{
				if(pActInfo->pEntity)
				{
					IEntityRenderProxy* pRenderProxy((IEntityRenderProxy*)pActInfo->pEntity->GetProxy(ENTITY_PROXY_RENDER));

					if (pRenderProxy)
					{
						IMaterial* pMtl(pRenderProxy->GetRenderMaterial(-1)); // material will be taken from the first renderable slot.
						if (pMtl)
						{
							const int subMtlCount = pMtl->GetSubMtlCount();
							for (int i = 0; i != subMtlCount; ++i)
							{
								IMaterial* pSubMat = pMtl->GetSubMtl(i);
								if (!pSubMat)
								{
									continue;
								}

								const SShaderItem& shaderItem(pSubMat->GetShaderItem());
								if (shaderItem.m_pShaderResources)
								{
									SEfResTexture* pTex = shaderItem.m_pShaderResources->GetTexture(0);
									if (pTex)
									{
										IDynTextureSource* pDynTexSrc = pTex->m_Sampler.m_pDynTexSource;
										if (pDynTexSrc)
										{
											IFlashPlayer* pFlashPlayer = (IFlashPlayer*) pDynTexSrc->GetSource(IDynTextureSource::DTS_I_FLASHPLAYER);
											if (pFlashPlayer)
											{
												const string& funcName = GetPortString(pActInfo, EIP_Function);
												SFlashVarValue args[2] = {GetPortInt(pActInfo, EIP_Int), GetPortFloat(pActInfo, EIP_Float)};
												pFlashPlayer->Invoke(funcName.c_str(), args, 2);
												break;
											}
										}
									}
								}
							}
						}
					}
				}
			}
			break;
		}
	}

	virtual void GetMemoryUsage(ICrySizer * s) const
	{
		s->Add(*this);
	}
};


REGISTER_FLOW_NODE( "MaterialFX:HUDStartFX", CHUDStartFXNode );
REGISTER_FLOW_NODE( "MaterialFX:HUDEndFX", CHUDEndFXNode );
REGISTER_FLOW_NODE( "MaterialFX:FlashInvokeOnObject", CMaterialFlashInvokeNode );
